package com.zsc.wxm.ysh.anjo.house.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.wxm.ysh.anjo.house.cache.ImagesCacheService;
import com.zsc.wxm.ysh.anjo.house.cache.PromiseCacheService;
import com.zsc.wxm.ysh.anjo.house.cache.ResourcesCacheService;
import com.zsc.wxm.ysh.anjo.house.feign.MemberService;
import com.zsc.wxm.ysh.anjo.house.mapper.PromiseMapper;
import com.zsc.wxm.ysh.anjo.house.model.Promise;
import com.zsc.wxm.ysh.anjo.house.model.Resources;
import com.zsc.wxm.ysh.anjo.house.service.PromiseService;
import com.zsc.wxm.ysh.anjo.house.service.RentHouseService;
import com.zsc.wxm.ysh.anjo.house.service.ResourcesService;
import com.zsc.wxm.ysh.anjo.result.PageResult;
import com.zsc.wxm.ysh.anjo.result.Result;
import com.zsc.wxm.ysh.anjo.service.base.enums.resources.HouseStatus;
import com.zsc.wxm.ysh.anjo.service.base.enums.resources.PromiseStatus;
import com.zsc.wxm.ysh.anjo.service.base.model.member.bo.MemberBO;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.dto.PromiseDTO;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.dto.RentHouseDTO;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.qo.PromiseQuery;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.vo.PromiseVO;
import com.zsc.wxm.ysh.anjo.utils.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 描述：
 *
 * @author playmaker
 * @since 2021/3/9 23:37
 */
@Service
@Slf4j
public class PromiseServiceImpl extends ServiceImpl<PromiseMapper, Promise> implements PromiseService {

    @Resource
    private ResourcesService resourcesService;

    @Resource
    private ResourcesCacheService resourcesCacheService;

    @Resource
    private MemberService memberService;

    @Resource
    private PromiseCacheService promiseCacheService;

    @Resource
    private ImagesCacheService imagesCacheService;

    @Resource
    private RentHouseService rentHouseService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(PromiseDTO param) {
        //前置判断----幂等性校验
        if (perCheck(param)) {
            return;
        }
        Promise promise = new Promise();
        BeanUtils.copyProperties(param, promise);
        promise.setStatus(PromiseStatus.SIGN_UP.getValue());
        this.save(promise);
        //清除缓存
        promiseCacheService.removeListByHouseIdCache(param.getHouseId());

        //更新房源信息为已出租
        Resources house = resourcesCacheService.getByIdCache(param.getHouseId());
        house.setStatus(HouseStatus.UNAVAILABLE.getValue());
        resourcesService.updateById(house);
        resourcesCacheService.removeByIdCache(house.getId());
    }

    private boolean perCheck(PromiseDTO param) {
        Optional<Promise> optional = promiseCacheService.getPromiseByHouseIdCache(param.getHouseId())
                .stream()
                .filter(x -> x.getRentUserId().equals(param.getRentUserId()))
                .filter(x -> x.getUserId().equals(param.getUserId()))
                .findFirst();
        if (optional.isPresent()) {
            Promise promise = optional.get();
            //如果合约没过期就不需要创建
            if (promise.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli() >
                    LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()) {
                return true;
            } else {
                //更新合约时间
                promise.setEndTime(param.getEndTime());
                this.updateById(promise);
                //清除缓存
                promiseCacheService.removeListByHouseIdCache(param.getHouseId());
            }
        }
        return false;
    }

    @Override
    public PageResult listPage(PromiseQuery query) {
        log.info("传入的参数, param={}", JSON.toJSONString(query));
        Page<Promise> page = new Page<>(query.getCurrPage(), query.getPageSize());
        LambdaQueryWrapper<Promise> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.orderByAsc(Promise::getStatus);
        if (query.getRentUserId() != null && query.getUserId() == null) {
            queryWrapper.eq(Promise::getRentUserId, query.getRentUserId());
        }
        if (query.getUserId() != null && query.getRentUserId() == null) {
            queryWrapper.eq(Promise::getUserId, query.getUserId());
        }
        if (query.getRentUserId() != null && query.getUserId() != null) {
            queryWrapper.eq(Promise::getUserId, query.getUserId()).or()
                    .eq(Promise::getRentUserId, query.getRentUserId());
        }
        if (query.getTimeStart() != null) {
            queryWrapper.ge(Promise::getCreateTime, query.getTimeStart());
        }
        if (query.getTimeEnd() != null) {
            queryWrapper.le(Promise::getCreateTime, query.getTimeEnd());
        }
        page = this.baseMapper.selectPage(page, queryWrapper);
        List<Promise> promises = page.getRecords();
        if (query.getStatus() != null) {
            promises = promises.stream().filter(x -> x.getStatus().equals(query.getStatus())).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(promises)) {
            return PageResult.ok(Collections.emptyList(), 0);
        }
        PageUtil pageUtil = new PageUtil(page);
        //搜集房源ids
        List<Long> houseIds = promises.stream().map(Promise::getHouseId).collect(Collectors.toList());
        //搜集租客ids
        List<Long> userIds = promises.stream().map(Promise::getRentUserId).collect(Collectors.toList());
        //批量获取房源
        log.info("houseId={}", houseIds);
        List<Resources> resources = new ArrayList<>();
        houseIds.forEach(x -> resources.add(resourcesCacheService.getByIdCache(x)));
        //批量获取用户信息
        Result result = memberService.getListByIds(userIds);
        String jsonData = JSON.toJSONString(result.getData().get("list"));
        List<MemberBO> memberBos = JSON.parseArray(jsonData, MemberBO.class);
        //组装VO
        List<PromiseVO> promiseVos = getPromiseVos(promises, resources, memberBos);
        return PageResult.ok(promiseVos, pageUtil.getTotal());
    }

    /**
     * 组装VO
     * @param promises 合约
     * @param resources 房源BO
     * @param memberBos 用户信息BO
     * @return List<PromiseVO>
     */
    private List<PromiseVO> getPromiseVos(List<Promise> promises, List<Resources> resources, List<MemberBO> memberBos) {
        List<PromiseVO> promiseVos = new ArrayList<>();
        for (int i = 0; i < promises.size(); i++) {
            PromiseVO promiseVo = new PromiseVO();
            promiseVo.setCreateTime(promises.get(i).getCreateTime());
            promiseVo.setId(promises.get(i).getId());
            promiseVo.setEndTime(promises.get(i).getEndTime());
            promiseVo.setHostName(resources.get(i).getConstact());
            promiseVo.setHouseId(resources.get(i).getId());
            promiseVo.setRentUserName(memberBos.get(i).getUsername());
            promiseVo.setStatus(PromiseStatus.getEnumDesc(promises.get(i).getStatus()));
            promiseVo.setHouseTitle(resources.get(i).getTitle());
            promiseVo.setHouseCode(resources.get(i).getCode());
            promiseVo.setRent(resources.get(i).getRent() + "元/月");
            promiseVo.setRentUserPhone(memberBos.get(i).getPhone());
            promiseVo.setHostPhone(resources.get(i).getPhone());
            promiseVo.setImage(imagesCacheService.listByResourcesIdCache(resources.get(i).getId()).get(0).getImageUrl());
            promiseVos.add(promiseVo);
        }
        return promiseVos;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePromise(Long id, Integer status, LocalDateTime endTime, Long houseId, Long rentUserId) {
        Promise promise = this.getById(id);
        if (status != null) {
            promise.setStatus(status);
        }
        if (endTime != null) {
            promise.setEndTime(endTime);
        }
        this.updateById(promise);
        //新增我的租房
        if (rentUserId != null && houseId != null) {
            rentHouseService.add(RentHouseDTO.builder().rentUserId(rentUserId).resourcesId(houseId).build());
        }
        promiseCacheService.removeListByHouseIdCache(promise.getHouseId());
    }

    @Override
    public List<Promise> getListByHouseIds(List<Long> houseIds) {
        List<Promise> list = new ArrayList<>();
        if (CollUtil.isNotEmpty(houseIds)) {
            houseIds.forEach(x -> list.addAll(promiseCacheService.getPromiseByHouseIdCache(x)));
        }
        return list;
    }


}
